package testApplets;

import processing.core.PApplet;
import simpleGeom.Grid3DFloat;
import simpleGeom.MMesh;
import simpleGeom.PGraphicsHelper;
import simpleGui.Gui;
import simpleGui.GuiSpinnerGroup;
import simpleGui.PCamera3D;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;

import marchingCubes.SimpleMCube;
import processing.core.PVector;

public class SimpleVoxelise extends PApplet {
	MMesh mesh; // a memory efficient class to store a mesh (only quads and triangles)
	SimpleMCube mc=new SimpleMCube(); // a memory efficient class for Marching-Cube Algorithm
	PCamera3D cam; // simple Camera class
	Grid3DFloat grid;// organizes a 3 dimensional float-grid
	String inputMeshPath="/Users/administrator/Desktop/Trumpet03.obj";
	String valuePath="/Users/administrator/Desktop/scanValues.txt";
	String outputMeshPath="/Users/administrator/Desktop/MeshEdit_0615_1/data/bunnyVoxelised.obj";
	boolean doScan=true;
	boolean scanBinary=false;
	boolean saveOBJ=false;
	public void setup() {
		size(1000, 700, P3D);
		cam=new PCamera3D(this);
		cam.setActive(true);
		cam.auto=true;
		// import mesh
		mesh = new MMesh();
		mesh.loadOBJ(inputMeshPath);
		mesh.triangulateQuads();
		if (doScan){
			// scan the geometry and save it
			scan(valuePath);
		}
		else{
			// load the values
			grid=new Grid3DFloat(valuePath);
		}
		mc.marchingCubes(grid.nX ,grid.nY , grid.nZ, grid.values, grid.dim*1.5f, grid.dim, grid.x1, grid.y1,
				grid.z1, null);
		if (saveOBJ){
			mc.saveObj(outputMeshPath);
		}
	}
	
	public void scan(String fileName){
		 float[] gridBounds=new float[6];
		mesh.calculateBounds(gridBounds);
		float dim = (gridBounds[3] - gridBounds[0]) / 20f;
		
		float offset=dim*2;
		gridBounds[0] -= offset ;
		gridBounds[1] -= offset ;
		gridBounds[2] -= offset ;
		gridBounds[3] += offset ;
		gridBounds[4] += offset ;
		gridBounds[5] += offset ;
		float dimX = gridBounds[3] - gridBounds[0];
		float dimY = gridBounds[4] - gridBounds[1];
		float dimZ = gridBounds[5] - gridBounds[2];
		dim = dimX / 20f;
		int nX = (int) (dimX / dim) + 2;
		int nY = (int) (dimY / dim) + 2;
		int nZ = (int) (dimZ / dim) + 2;
		println("nX: " + nX + "  nY: " + nY + "  nZ: " + nZ);
		grid=new Grid3DFloat(nX,nY,nZ);
		grid.x1=gridBounds[0];
		grid.y1=gridBounds[1];
		grid.z1=gridBounds[2];
		grid.dim=dim;
		
		if (scanBinary) {
			// scanning binary if inside 1==inside 0==out
			MMesh.scanMeshBinary2(mesh.xc, mesh.yc, mesh.zc, mesh.triangles,
					gridBounds[0], gridBounds[1], gridBounds[2], nX, nY, nZ,
					dim, grid.values);
		} else {
			// scanning the distance to mesh
			MMesh.scanMeshDistance(mesh.xc, mesh.yc, mesh.zc, mesh.triangles,
					gridBounds[0], gridBounds[1], gridBounds[2], nX, nY, nZ,
					dim, dim * 2f, grid.values);
		}
		grid.saveValues(valuePath);
		
	}
		
	public void draw() {
		println("draw");
		background(0);
		//cam.apply(g);
		camera(500,0,0,0,0,0,0,0,1);
		rotateY(PI);
		rotateZ(frameCount/100f);
		lights();
		
		pointLight(100,100,100,200,200,200);
		PCamera3D.drawWorldAxis3D(g, 100);
		float dimX = grid.x2() - grid.x1();
		scale(300 / dimX);
		translate(-grid.cX(),-grid.cY(),-grid.cZ());
		noFill();
		stroke(255, 0, 0);
		mesh.draw( g);
		noStroke();
		fill(255);
		mc.draw(g);
	}
	
	
}
